package org.kazuhiko.pokemon3d.utility;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.lwjgl.util.vector.Vector2f;
import org.lwjgl.util.vector.Vector3f;
import org.newdawn.slick.opengl.Texture;

import static org.lwjgl.opengl.GL11.*;

public class Model
{
	private final List<Vector3f> vertices = new ArrayList<Vector3f>();
	private final List<Vector3f> normals = new ArrayList<Vector3f>();
	
	private final List<Vector2f> textureCoordinates = new ArrayList<Vector2f>();
	
	private final List<Face> faces = new ArrayList<Face>();
	
	private final HashMap<String, Material> materials = new HashMap<String, Material>();
	
	private boolean enableSmoothShading = true;
	
	private float width;
	private float height;
	private float depth;
	
	public void enableStates()
	{
		if( hasTextureCoordinates() )
		{
			glEnable( GL_TEXTURE_2D );
		}
		if( isSmoothShadingEnabled() )
		{
			glShadeModel( GL_SMOOTH );
		}
		else
		{
			glShadeModel( GL_FLAT );
		}
	}
	
	public float getWidth()
	{
		return width;
	}
	
	public void setWidth( float width )
	{
		this.width = width;
	}
	
	public float getHeight()
	{
		return height;
	}
	public void setHeight( float height )
	{
		this.height = height;
	}
	
	public float getDepth()
	{
		return depth;
	}
	
	public void setDepth( float depth )
	{
		this.depth = depth;
	}
	
	public boolean hasTextureCoordinates()
	{
		return getTextureCoordinates().size() > 0;
	}
	
	public boolean hasNormals()
	{
		return getNormals().size() > 0;
	}
	
	public List<Vector3f> getVertices()
	{
		return vertices;
	}
	
	public List<Vector2f> getTextureCoordinates()
	{
		return textureCoordinates;
	}
	
	public List<Vector3f> getNormals()
	{
		return normals;
	}
	
	public List<Face> getFaces()
	{
		return faces;
	}
	
	public boolean isSmoothShadingEnabled()
	{
		return enableSmoothShading;
	}
	
	public void setSmoothShadingEnabled( boolean smoothShadingEnabled )
	{
		this.enableSmoothShading = smoothShadingEnabled;
	}
	
	public HashMap<String, Material> getMaterials()
	{
		return materials;
	}
	
	public static class Face
	{
		private final int[] vertexIndices = { -1, -1, -1 };
		private final int[] normalIndices = { -1, -1, -1 };
		private final int[] textureCoordinateIndices = { -1, -1, -1 };
		
		private Material material;
		
		public Face( int[] vertexIndices )
		{
			this.vertexIndices[ 0 ] = vertexIndices[ 0 ];
			this.vertexIndices[ 1 ] = vertexIndices[ 1 ];
			this.vertexIndices[ 2 ] = vertexIndices[ 2 ];
		}
		
		public Face( int[] vertexIndices, int[] normalIndices )
		{
			this.vertexIndices[ 0 ] = vertexIndices[ 0 ];
			this.vertexIndices[ 1 ] = vertexIndices[ 1 ];
			this.vertexIndices[ 2 ] = vertexIndices[ 2 ];
			
			this.normalIndices[ 0 ] = normalIndices[ 0 ];
			this.normalIndices[ 1 ] = normalIndices[ 1 ];
			this.normalIndices[ 2 ] = normalIndices[ 2 ];
		}
		
		public Face( int[] vertexIndices, int[] normalIndices, int[] textureCoordinateIndices, Material material )
		{
			this.vertexIndices[ 0 ] = vertexIndices[ 0 ];
			this.vertexIndices[ 1 ] = vertexIndices[ 1 ];
			this.vertexIndices[ 2 ] = vertexIndices[ 2 ];
			
			this.textureCoordinateIndices[ 0 ] = textureCoordinateIndices[ 0 ];
			this.textureCoordinateIndices[ 1 ] = textureCoordinateIndices[ 1 ];
			this.textureCoordinateIndices[ 2 ] = textureCoordinateIndices[ 2 ];
			
			this.normalIndices[ 0 ] = normalIndices[ 0 ];
			this.normalIndices[ 1 ] = normalIndices[ 1 ];
			this.normalIndices[ 2 ] = normalIndices[ 2 ];
			
			this.material = material;
		}
		
		public Material getMaterial()
		{
			return material;
		}
		
		public boolean hasNormals()
		{
			return normalIndices[ 0 ] != -1;
		}
		
		public boolean hasTextureCoordinates()
		{
			return textureCoordinateIndices[ 0 ] != -1;
		}
		
		public int[] getVertexIndices()
		{
			return vertexIndices;
		}
		
		public int[] getTextureCoordinateIndices()
		{
			return textureCoordinateIndices;
		}
		
		public int[] getNormalIndices()
		{
			return normalIndices;
		}
	}
	
	public static class Material
	{
		public float specularCoefficient = 100;
		
		public float[] ambientColour = { 0.2f, 0.2f, 0.2f };
		public float[] diffuseColour = { 0.3f, 1, 1 };
		public float[] specularColour = { 1, 1, 1 };
		
		public Texture texture;
		
		@Override
		public String toString()
		{
			return 	"Material{ " +
					"specularCoefficient=" + specularCoefficient +
					", ambientColor=" + ambientColour + 
					", diffuseColour=" + diffuseColour + 
					", specularColour=" + specularColour + 
					"}";
		}
	}
}
